package com.yugao.fintech.framework.assistant.sign;

import com.yugao.fintech.framework.assistant.core.exception.Assert;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SignPayload {
    /**
     * 时间戳
     */
    public static final String TIME_STAMP = "ts";
    /**
     * 签名数据
     */
    public static final String SIGN = "sign";
    /**
     * 随机数，客户端生成随机数主要保证签名的多变性
     */
    public static final String NONCE = "nonce";
    /**
     * 密钥id
     */
    public static final String SECRET_ID = "secretId";
    public static final String SECRET_KEY = "secretKey";
    /**
     * 签名类型, 比如md5/sha256
     */
    public static final String SIGN_TYPE = "signType";

    /**
     * 时间戳
     */
    private String timeStamp;

    /**
     * 签名
     */
    private String sign;

    /**
     * 随机数，生成签名方生成随机数主要保证签名的多变性
     */
    private String nonce;

    /**
     * 密钥id
     */
    private String secretId;

    /**
     * 签名类型
     */
    private String signType;

    public void check() {
        // 判断需要的参数是否为空，不为空进行后续操作
        Assert.isFalse(StringUtils.isEmpty(nonce) || "null".equalsIgnoreCase(nonce), NONCE + "不能为空");
        Assert.isFalse(StringUtils.isEmpty(sign) || "null".equalsIgnoreCase(sign), SIGN + "不能为空");
        Assert.isFalse(StringUtils.isEmpty(secretId) || "null".equalsIgnoreCase(secretId), SECRET_ID + "不能为空");
        Assert.isFalse(StringUtils.isEmpty(timeStamp) || "null".equalsIgnoreCase(timeStamp), TIME_STAMP + "不能为空");
        Assert.isFalse(StringUtils.isEmpty(signType) || "null".equalsIgnoreCase(signType), SIGN_TYPE + "不能为空");
    }

    public static String[] getAllPayload() {
        return new String[]{SIGN, SECRET_ID, SECRET_KEY, NONCE, TIME_STAMP, SIGN_TYPE};
    }

    /**
     * 转成map
     */
    public Map<String, Object> toMapOfObjectType() {
        Map<String, Object> map = new HashMap<>();
        map.put(SECRET_ID, this.secretId);
        map.put(NONCE, this.nonce);
        map.put(SIGN, this.sign);
        map.put(TIME_STAMP, this.timeStamp);
        map.put(SIGN_TYPE, this.signType);
        return map;
    }

    public Map<String, String> toMapOfStringType() {
        Map<String, String> map = new HashMap<>();
        map.put(NONCE, this.nonce);
        map.put(SECRET_ID, this.secretId);
        map.put(SIGN, this.sign);
        map.put(TIME_STAMP, this.timeStamp);
        map.put(SIGN_TYPE, this.signType);
        return map;
    }


    public Map<String, List<String>> toMultiValueMapForStringType() {
        Map<String, List<String>> map = new HashMap<>();
        map.put(SECRET_ID, Collections.singletonList(this.secretId));
        map.put(NONCE, Collections.singletonList(this.nonce));
        map.put(TIME_STAMP, Collections.singletonList(this.timeStamp));
        map.put(SIGN_TYPE, Collections.singletonList(this.signType));
        map.put(SIGN, Collections.singletonList(this.sign));
        return map;
    }

    public static SignPayload buildByMapOfStringType(Map<String, String> map) {
        return SignPayload.builder()
                .nonce(map.get(NONCE)).signType(map.get(SIGN_TYPE)).timeStamp(map.get(TIME_STAMP))
                .sign(map.get(SIGN)).secretId(map.get(SECRET_ID))
                .build();
    }

    public static SignPayload buildByFunction(Function<String, String> function) {
        Map<String, String> map = new HashMap<>();
        for (String key : getAllPayload()) {
            map.put(key, function.apply(key));
        }
        return SignPayload.builder()
                .nonce(map.get(NONCE)).signType(map.get(SIGN_TYPE)).timeStamp(map.get(TIME_STAMP))
                .sign(map.get(SIGN)).secretId(map.get(SECRET_ID))
                .build();
    }

    public static SignPayload buildByMapOfObjectType(Map<String, Object> map) {
        return SignPayload.builder()
                .nonce(String.valueOf(map.get(NONCE))).signType(String.valueOf(map.get(SIGN_TYPE)))
                .timeStamp(String.valueOf(map.get(TIME_STAMP)))
                .sign(String.valueOf(map.get(SIGN))).secretId(String.valueOf(map.get(SECRET_ID)))
                .build();
    }

    public static SignPayload buildByMultiValueMapOfStringType(Map<String, List<String>> map) {
        return SignPayload.builder()
                .nonce(getFirst(map, NONCE)).signType(getFirst(map, SIGN_TYPE)).timeStamp(getFirst(map, TIME_STAMP))
                .sign(getFirst(map, SIGN)).secretId(getFirst(map, SECRET_ID))
                .build();
    }

    private static String getFirst(Map<String, List<String>> map, String key) {
        return map.getOrDefault(key, Collections.emptyList()).stream().findFirst().orElse(null);
    }
}
